

#region Using Statements
using System;
using System.Collections.Generic;//using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion



namespace Pauliver
{
    public class AI
    {
        protected enum FiniteStateMachine { MoveTowardsHealthPack, PickTarget, MoveTowardsTarget, JetPack, FindHigherGround, SelectWeapon, Deploy, AimBegin, AimEnd, FireRight, FireLeft, Run, EndTurn };

        protected FakeGamePad gamepad;
        protected Team myteam;
        protected FiniteStateMachine state;
        protected Vector2 TargetPosition;
        protected PlayerObject Me;
        protected float NextEventAt = 0;
        protected Vector2 direction;
        protected PlayerObject Enemy;


        protected UserTeamPlayerManager UTPM;

        public AI(FakeGamePad gp,UserTeamPlayerManager p_UTPM)
        {
            UTPM = p_UTPM;
            gamepad = gp;
            Me = UTPM.CurrentAvatar;
            myteam = Me.Team;
            Vector2 position = Me.Position();
            state = FiniteStateMachine.PickTarget;

            UserTeamPlayer target;
            {// Pick which team to attack
                LinkedList<UserTeamPlayer> pms = UTPM.PlayerManagers;
                if (pms.First.Value.Team != myteam)
                {
                    target = pms.First.Value;
                }
                else
                {
                    target = pms.Last.Value;
                }
                int currentMax = target.TotalHP();
                foreach (UserTeamPlayer utp in pms)
                {
                    if (utp.TotalHP() >= currentMax && utp.Team != myteam)
                    {
                        target = utp;
                        // Since AI should always be the last player index
                        // AI will attack other AI if all HP are equal
                        // This lets our players "win" more often which players like
                        // to change this make it > currentMax not >= currentMax
                    }
                }
            }
            {// Pick which avatar to attack
                float distance = 8000;
                foreach (PlayerObject enemy in target.Avatars)
                {
                    Vector2 enemyposition = enemy.Position();
                    float newdistance = (enemyposition - position).X;
                    if ( Math.Abs(newdistance) < Math.Abs(distance) )
                    {
                        distance = newdistance;
                        TargetPosition = enemyposition;
                    }
                }
            }
            direction = Vector2.Zero;
        }

        public virtual void Update(float ElapsedTime)
        {
            Vector2 position = Me.Position();
            float distance = (TargetPosition - position).X;
            switch(state)
            {
                case FiniteStateMachine.PickTarget:
                    {
                        if (ElapsedTime > 2.0f)
                        {
                            state = FiniteStateMachine.MoveTowardsTarget;
                            NextEventAt = ElapsedTime;
                        }
                    }
                    break;
                case FiniteStateMachine.MoveTowardsTarget:
                    {
                        const int MaxShotDistance = 375;
                        const int MinShot = 32;
                        if (distance > MaxShotDistance)
                        {
                            gamepad.SetLeftStickState(new Vector2(1.0f, 0.0f));
                        }
                        else if (distance < -MaxShotDistance)
                        {
                            gamepad.SetLeftStickState(new Vector2(-1.0f, 0.0f));
                        }
                        else if(distance > -MinShot && distance < MinShot && direction == Vector2.Zero)
                        {
                            if (distance > 0)
                            {
                                if (position.X < 1870)
                                {
                                    direction = new Vector2(1.0f, 0.0f);
                                    gamepad.SetLeftStickState(direction);
                                }
                                else
                                {
                                    direction = new Vector2(-1.0f, 0.0f);
                                    gamepad.SetLeftStickState(direction);
                                }

                            }
                            else if (distance <= 0)
                            {
                                if (position.X > 50)
                                {
                                    direction = new Vector2(-1.0f, 0.0f);
                                    gamepad.SetLeftStickState(direction);
                                }
                                else
                                {
                                    direction = new Vector2(1.0f, 0.0f);
                                    gamepad.SetLeftStickState(direction);
                                }
                            }
                        }
                        else if (distance > -MinShot && distance < MinShot && direction != Vector2.Zero)
                        {
                            gamepad.SetLeftStickState(direction);
                        }
                        else
                        {
                            state = FiniteStateMachine.FindHigherGround;
                            NextEventAt = ElapsedTime + 0.2f;
                        }
                    }
                    break;
                case FiniteStateMachine.FindHigherGround:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            state = FiniteStateMachine.SelectWeapon;
                            NextEventAt = ElapsedTime + 0.1f;
                        }
                        else
                        {
                            if (distance > 0.0f)
                            {
                                gamepad.SetLeftStickState(new Vector2(1.0f, 0.0f));
                            }
                            else if (distance < 0.0f)
                            {
                                gamepad.SetLeftStickState(new Vector2(-1.0f, 0.0f));
                            }
                        }
                    }
                    break;
                case FiniteStateMachine.SelectWeapon:
                    {
                        AvailableWeaponList weapons = this.UTPM.Current.AvailableWeapons;
                        
                        state = SelectWeapon(ElapsedTime, (int) AvailableWeaponList.LauncherType.ClusterLauncher);
                    }
                    break;
                case FiniteStateMachine.Deploy:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                            NextEventAt = ElapsedTime + 0.8f;
                            state = FiniteStateMachine.AimBegin;
                        }
                    }
                    break;
                case FiniteStateMachine.AimBegin:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            NextEventAt = ElapsedTime + 0.2125f;
                            state = FiniteStateMachine.AimEnd;
                        }
                    }
                    break;
                case FiniteStateMachine.AimEnd:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                            NextEventAt = ElapsedTime + 7.5f;
                            if (Me.GetFacing() == Facing.Left)
                            {
                                state = FiniteStateMachine.FireLeft;
                            }
                            else if(Me.GetFacing() == Facing.Right)
                            {
                                state = FiniteStateMachine.FireRight;
                            }else{
                                //Now what?
                            }
                        }
                        else
                        {
                            gamepad.SetLeftStickState(new Vector2(0.0f, 1.0f));
                        }
                    }
                    break;
                case FiniteStateMachine.FireRight:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                            state = FiniteStateMachine.Run;
                            NextEventAt = ElapsedTime + 4.0f;
                        }
                        else
                        {
                            float distance2 = TargetPosition.X - (Game1.Instance.CurrentViewport.X + (0.5f * Game1.Instance.CurrentViewport.Width));

                            if (distance2 > -1.5f)
                            {
                                gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                            }
                            else
                            {
                                state = FiniteStateMachine.Run;
                                NextEventAt = ElapsedTime + 4.0f;
                            }
                        }
                    }
                    break;
                case FiniteStateMachine.FireLeft:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                            state = FiniteStateMachine.Run;
                            NextEventAt = ElapsedTime + 4.0f;
                        }
                        else
                        {
                            float distance2 = TargetPosition.X - (Game1.Instance.CurrentViewport.X + (0.5f * Game1.Instance.CurrentViewport.Width));

                            if (distance2 < 1.5f ) 
                            {
                                gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                            }
                            else
                            {
                                state = FiniteStateMachine.Run;
                                NextEventAt = ElapsedTime + 4.0f;
                            }
                        }
                    }
                    break;
                case FiniteStateMachine.Run:
                    {
                        if (ElapsedTime > NextEventAt)
                        {
                            //@@ always move 1 unit to re-center camera
                            if (distance > 0)
                            {
                                gamepad.SetLeftStickState(new Vector2(1.0f, 0.0f));
                            }
                            else if (distance < 0)
                            {
                                gamepad.SetLeftStickState(new Vector2(-1.0f, 0.0f));
                            }
                            state = FiniteStateMachine.EndTurn;
                            NextEventAt = ElapsedTime;
                        }
                    }
                    break;
                case FiniteStateMachine.EndTurn:
                    {
                        //clear all old input
                        gamepad.Update();
                        gamepad.SetState(Buttons.Back, ButtonWrapper.ButtonState.Pressed);
                    }
                    break;
                default:
                    break;
            }
        }


        int upcount = 0;
        int targetUpcount = 0;
        bool Flag = true; //allow you to select the item at 0,0
        protected virtual FiniteStateMachine SelectWeapon(float ElapsedTime, int target)
        {
            if (ElapsedTime > NextEventAt)
            {
                if (upcount == 0 && targetUpcount == 0 && Flag)
                {
                    ((FakeButtonWrapper)gamepad.B).ClearRegisterDown();
                    gamepad.SetState(Buttons.B, InputWrapper.ButtonState.Held);
                    targetUpcount = target;
                    Flag = false;
                }
                else if (upcount == targetUpcount)
                {
                    upcount = 0;
                    targetUpcount = 0;
                    NextEventAt = ElapsedTime + 0.5f;
                    ((FakeButtonWrapper)gamepad.DPadUp).ClearRegisterDown();
                    ((FakeButtonWrapper)gamepad.B).ClearRegisterDown();
                    ((FakeButtonWrapper)gamepad.A).ClearRegisterDown();
                    gamepad.SetState(Buttons.A, InputWrapper.ButtonState.Held);
                    return FiniteStateMachine.Deploy;
                }
                else
                {
                    upcount++;
                    ((FakeButtonWrapper)gamepad.DPadUp).ClearRegisterDown();
                    ((FakeButtonWrapper)gamepad.DPadUp).SetHeld();
                    //gamepad.SetState(Buttons.DPadUp, InputWrapper.ButtonState.Held);
                    NextEventAt = ElapsedTime + 1.0f;
                }
                NextEventAt = ElapsedTime + 0.5f;
            } 
            return state;

        }
    }
}